﻿package openglhandmaid
{
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.geom.Vector3D;
	import flash.geom.Matrix;
	import flash.display.BitmapData;
	import flash.display.Bitmap;
	import flash.display.Sprite;

	public class Main extends Sprite
	{
		private var bitmapWidth:int = 500;
		private var bitmapHeight:int = 500;
		private var bitmap:Bitmap;
		
		public function Main()
		{
			setup();
			
			//testDrawLine();
			//testDrawAfricanHead();
			//testDrawTriangles();
			//testFillAfricanHead();
			//testFillAfricanHeadWithZBuffer();
			testFillAfricanHeadWithUV();
			
			bitmap.bitmapData = flipBitmapData(bitmap.bitmapData, "y");
		}
		private function setup():void
		{
			stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.stageFocusRect = false;
		}		
		private function flipBitmapData(original:BitmapData, axis:String = "x"):BitmapData
		{
		     var flipped:BitmapData = new BitmapData(original.width, original.height, true, 0);
		     var matrix:Matrix;
		     if(axis == "x")
		     {
		          matrix = new Matrix( -1, 0, 0, 1, original.width, 0);
		     }
		     else
		     {
		          matrix = new Matrix( 1, 0, 0, -1, 0, original.height);
		     }
		     flipped.draw(original, matrix, null, null, null, true);
		     return flipped;
		}
		
		// ====================================================================================================
		
		private function testFillAfricanHeadWithUV():void
		{
			bitmap = addChild( new Bitmap(new BitmapData(bitmapWidth, bitmapHeight, false, 0)) ) as Bitmap;
			
			var zbuffer:Array = new Array(bitmap.width*bitmap.height).map( function(element:*, index:int, arr:Array):int{return -1000000000;} );
			
			var bm:Bresenham = new Bresenham();
			
			var objparser:Model = new Model();
			var vertices:Vector.<Vector3D> = objparser.getVertices();
			var faces:Vector.<Array> = objparser.getFaces();
			
			var length:int = faces.length;
			var scale:int = width/2;
			var face:Array;
			for (var i:int=0; i<length; i++) 
			{
		        face = faces[i];
				
				var t0:Vector3D = vertices[face[0]-1];
				var t1:Vector3D = vertices[face[3]-1];
				var t2:Vector3D = vertices[face[6]-1];
				
					t0 = new Vector3D( (t0.x+1)*scale, (t0.y+1)*scale, (t0.z+1)*scale );
					t1 = new Vector3D( (t1.x+1)*scale, (t1.y+1)*scale, (t1.z+1)*scale);
					t2 = new Vector3D( (t2.x+1)*scale, (t2.y+1)*scale, (t2.z+1)*scale);
				// -------
				var arr:Array = [t0, t1, t2];
				var screen_coords:Vector.<Vector3D> = new Vector.<Vector3D>();
				var world_coords:Vector.<Vector3D> = new Vector.<Vector3D>();
				for (var j:int=0; j<3; j++) 
				{
				    var v:Vector3D = vertices[face[j*3]-1];
				    screen_coords.push(arr[j]);
		            world_coords.push(v);
				}
				
				var n:Vector3D = Vector3D(world_coords[2].subtract(world_coords[0])).crossProduct(Vector3D(world_coords[1].subtract(world_coords[0])));
					n.normalize();
				var light_dir:Vector3D = new Vector3D(0,0,-1);
				var intensity:Number = n.x*light_dir.x + n.y*light_dir.y + n.z*light_dir.z;
				
				if (intensity>0) 
				{
					//Объединение компонентов цвета:
					var r:uint = intensity*255;
					var g:uint = intensity*255;
					var b:uint = intensity*255;
					var color:uint = r << 16 | g << 8 | b;
					var uv:Vector.<Vector3D> = new Vector.<Vector3D>();
					for (var k:int=1; k<=7; k+=3) 
					{
					    uv.push( objparser.getUV(i, k) );
					}
					bm.triangleWithUV(V3dUtil.setInt(screen_coords[0]), V3dUtil.setInt(screen_coords[1]), V3dUtil.setInt(screen_coords[2]), uv[0], uv[1], uv[2], objparser.diffusemap, bitmap.bitmapData, color, zbuffer);
		        }				
		    }		    
		}
		
		private function testFillAfricanHeadWithZBuffer():void
		{
			bitmap = addChild( new Bitmap(new BitmapData(bitmapWidth, bitmapHeight, false, 0)) ) as Bitmap;
			
			var zbuffer:Array = new Array(bitmap.width*bitmap.height).map( function(element:*, index:int, arr:Array):int{return -1000000000;} );
			
			var bm:Bresenham = new Bresenham();
			
			var objparser:Model = new Model();
			var vertices:Vector.<Vector3D> = objparser.getVertices();
			var faces:Vector.<Array> = objparser.getFaces();
			
			var length:int = faces.length;
			var scale:int = width/2;
			var face:Array;
			for (var i:int=0; i<length; i++) 
			{
		        face = faces[i];
				
				var t0:Vector3D = vertices[face[0]-1];
				var t1:Vector3D = vertices[face[3]-1];
				var t2:Vector3D = vertices[face[6]-1];
				
					t0 = new Vector3D( (t0.x+1)*scale, (t0.y+1)*scale, (t0.z+1)*scale );
					t1 = new Vector3D( (t1.x+1)*scale, (t1.y+1)*scale, (t1.z+1)*scale);
					t2 = new Vector3D( (t2.x+1)*scale, (t2.y+1)*scale, (t2.z+1)*scale);
					
				// -------
				var arr:Array = [t0, t1, t2];
				var screen_coords:Vector.<Vector3D> = new Vector.<Vector3D>();
				var world_coords:Vector.<Vector3D> = new Vector.<Vector3D>();
				for (var j:int=0; j<3; j++) 
				{
				    var v:Vector3D = vertices[face[j*3]-1];
				    screen_coords.push(arr[j]);
		            world_coords.push(v);
				}
				
				var n:Vector3D = Vector3D(world_coords[2].subtract(world_coords[0])).crossProduct(Vector3D(world_coords[1].subtract(world_coords[0])));
					n.normalize();
				var light_dir:Vector3D = new Vector3D(0,0,-1);
				var intensity:Number = n.x*light_dir.x + n.y*light_dir.y + n.z*light_dir.z;
				
				if (intensity>0) 
				{
					//Объединение компонентов цвета:
					var r:uint = intensity*255;
					var g:uint = intensity*255;
					var b:uint = intensity*255;
					var color:uint = r << 16 | g << 8 | b;
					
					bm.triangleWithZBuffer(V3dUtil.setInt(screen_coords[0]), V3dUtil.setInt(screen_coords[1]), V3dUtil.setInt(screen_coords[2]), bitmap.bitmapData, color, zbuffer);
		        }				
		    }		    
		}
		
		private function testFillAfricanHead():void
		{
			bitmap = addChild( new Bitmap(new BitmapData(bitmapWidth, bitmapHeight, false, 0)) ) as Bitmap;
			var bm:Bresenham = new Bresenham();
			
			var objparser:Model = new Model();
			var vertices:Vector.<Vector3D> = objparser.getVertices();
			var faces:Vector.<Array> = objparser.getFaces();
			
			var length:int = faces.length;
			var scale:int = width/2;
			
			var face:Array;
			
			for (var i:int=0; i<length; i++) 
			{
		        face = faces[i];
				
				var t0:Vector3D = vertices[face[0]-1];
				var t1:Vector3D = vertices[face[3]-1];
				var t2:Vector3D = vertices[face[6]-1];
				
					t0 = new Vector3D( (t0.x+1)*scale, (t0.y+1)*scale, (t0.z+1)*scale );
					t1 = new Vector3D( (t1.x+1)*scale, (t1.y+1)*scale, (t1.z+1)*scale);
					t2 = new Vector3D( (t2.x+1)*scale, (t2.y+1)*scale, (t2.z+1)*scale);
				// -------
				var arr:Array = [t0, t1, t2];
				var screen_coords:Vector.<Vector3D> = new Vector.<Vector3D>();
				var world_coords:Vector.<Vector3D> = new Vector.<Vector3D>();
				for (var j:int=0; j<3; j++) 
				{
				    var v:Vector3D = vertices[face[j*3]-1];
				    screen_coords.push(arr[j]);
		            world_coords.push(v);
				}
				
				var n:Vector3D = Vector3D(world_coords[2].subtract(world_coords[0])).crossProduct(Vector3D(world_coords[1].subtract(world_coords[0])));
					n.normalize();
				var light_dir:Vector3D = new Vector3D(0,0,-1);
					
		        var intensity:Number = n.x*light_dir.x + n.y*light_dir.y + n.z*light_dir.z;
				
				if (intensity>0) 
				{
					//Объединение компонентов цвета:
					var r:uint = intensity*255;
					var g:uint = intensity*255;
					var b:uint = intensity*255;
					var color:uint = r << 16 | g << 8 | b;
					
					bm.triangleBitmap(V3dUtil.setInt(screen_coords[0]), V3dUtil.setInt(screen_coords[1]), V3dUtil.setInt(screen_coords[2]), bitmap.bitmapData, color);
		        }				
		    }		    
		}
		
		private function testDrawTriangles():void
		{
			bitmap = addChild( new Bitmap(new BitmapData(bitmapWidth, bitmapHeight, false, 0)) ) as Bitmap;
			
			var image:BitmapData = bitmap.bitmapData;
			var white:Number = 0xffffff;
			var red:Number = 0xff0000;
			var green:Number = 0x00ff00;
			
			var b:Bresenham = new Bresenham();
			
			var v0:Array = [new Vector3D(10, 70), new Vector3D(50, 160), new Vector3D(70, 80)];
			var v1:Array = [new Vector3D(180, 50), new Vector3D(150, 1), new Vector3D(70, 180)];
			var v2:Array = [new Vector3D(180, 150), new Vector3D(120, 160), new Vector3D(130, 180)];
			
			b.triangleBitmap(v0[0], v0[1], v0[2], image, red);
			b.triangleBitmap(v1[0], v1[1], v1[2], image, green);
			b.triangleBitmap(v2[0], v2[1], v2[2], image, white);
		}
		
		private function testDrawAfricanHead():void
		{
			bitmap = addChild( new Bitmap(new BitmapData(bitmapWidth, bitmapHeight, false, 0)) ) as Bitmap;
			var b:Bresenham = new Bresenham();
			
			var objparser:Model = new Model();
			var vertices:Vector.<Vector3D> = objparser.getVertices();
			var faces:Vector.<Array> = objparser.getFaces();
			
			var length:int = faces.length;
			
			var face:Array;
			var faceLength:int;
			
			for (var i:int=0; i<length; i++) {
		        face = faces[i];
		        faceLength = face.length;
		        for (var j:int=0; j<faceLength; j+=3) 
		        {
		        	var v0:Vector3D = vertices[face[j]-1];
		            var v1:Vector3D = vertices[face[((j+3)%faceLength)]-1];
		            var x0:Number = (v0.x+1.)*width/2.;
		            var y0:Number = (v0.y+1.)*height/2.;
		            var x1:Number = (v1.x+1.)*width/2.;
		            var y1:Number = (v1.y+1.)*height/2.;
		            
		            b.line(x0, y0, x1, y1, bitmap.bitmapData, 0xffffff);		            
		        }
		    }
		}
		
		private function testDrawLine():void
		{
			bitmap = addChild( new Bitmap(new BitmapData(bitmapWidth, bitmapHeight, false, 0)) ) as Bitmap;
			
			var image:BitmapData = bitmap.bitmapData;
			var white:Number = 0xffffff;
			var red:Number = 0xff0000;
			
			var b:Bresenham = new Bresenham();
			
			b.line(13, 20, 80, 40, image, white);
			b.line(20, 13, 40, 80, image, red);
			b.line(80, 40, 13, 20, image, red);
		}
	}
}